// file: eeprom.c
// author: Sebastian Steppeler copyright 2012
/*license: This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.*/

#include <avr/io.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <util/delay.h>
#include <util/twi.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#include "typedefs.h"
#include "timer.h"
#include "Midi.h"
#include "ADC.h"
#include "eeprom.h"
#include "main.h"
#include "pedal.h"


// eeprom adresses:
#define EE_DUMMY      0x000
#define EE_DATAVERSION	( EE_DUMMY + sizeof( uint8_t ) )
#define EE_NUMMODULES ( EE_DATAVERSION + sizeof( uint8_t ) )
#define EE_CBASENOTE ( EE_NUMMODULES + sizeof( uint8_t ) )
#define EE_PEDALS (EE_CBASENOTE + sizeof( PEDAL)*3)


// globals:
uint16_t iCurrentAddress;

// externs:
extern unsigned char cNumModules;
extern unsigned char cBaseNote;
extern PEDAL Pedals[3];


// eeprom adresses:
#define EE_DUMMY      0x000
#define EE_DATAVERSION	( EE_DUMMY + sizeof( uint8_t ) )
#define EE_REST ( EE_DATAVERSION + sizeof( uint8_t ) )

// globals:
uint16_t iCurrentAddress;

// externs:
extern PEDAL Pedals[3];
extern volatile int8_t cPolarity;


void eeprom_set_start_address(uint16_t iStartAddress)
{
	iCurrentAddress = iStartAddress;
}

uint16_t eeprom_read_word_inc(void)
{
	uint16_t iMyWord;

	/*iMyWord = eeprom_read_word((uint16_t*)iCurrentAddress);
	iCurrentAddress += sizeof(uint16_t);*/
	*((uint8_t*)&iMyWord) = eeprom_read_byte_inc();
	*(((uint8_t*)&iMyWord)+1) = eeprom_read_byte_inc();

	return iMyWord;
}

void eeprom_write_word_inc(uint16_t data)
{	
	eeprom_write_byte_inc(*(((uint8_t*)&data)));
	eeprom_write_byte_inc(*(((uint8_t*)&data)+1));
}

uint8_t eeprom_read_byte_inc(void)
{
	uint8_t iMyByte;

	iMyByte = eeprom_read_byte((uint8_t*)iCurrentAddress);
	iCurrentAddress += sizeof(uint8_t);
	return iMyByte;
}

void eeprom_write_byte_inc(uint8_t data)
{
	uint8_t iMyByte;
	
	// write byte only when there is an actual change of eeprom content neccessary:
	iMyByte = eeprom_read_byte((uint8_t*)iCurrentAddress);
	if(iMyByte!=data)
	{
		eeprom_write_byte((uint8_t*)iCurrentAddress, data);
		iMyByte = eeprom_read_byte((uint8_t*)iCurrentAddress);
		if(iMyByte!=data)
		{
			// TO ADD: Error handling for dead eeprom cells:
		}
	}

	iCurrentAddress += sizeof(uint8_t);
}



bool EELoadSettings(void)
{
	uint8_t temp;
	
	eeprom_set_start_address(0);
	// read and check corruption state:
	temp = eeprom_read_byte_inc();
	if(temp != 0x00)
		return false;

	// read and check data software version:
	temp = eeprom_read_byte_inc();
	if(temp != SW_VERSION)
		return false;
		
	cPolarity = (int8_t)eeprom_read_byte_inc();

	char n = 0;
	for(n=0;n<3;n++)
	{
		Pedals[(int)n].iMin = eeprom_read_word_inc();
		Pedals[(int)n].iMax = eeprom_read_word_inc();
		Pedals[(int)n].iFactor = eeprom_read_word_inc();
	}

	return true;
}


void EESaveSettings(void)
{
	eeprom_set_start_address(0);
	// initiate eeprom update by setting busy flags:
	eeprom_write_byte_inc(0xff);

	// write our current software version:
	eeprom_write_byte_inc(SW_VERSION);

	eeprom_write_byte_inc((uint8_t)cPolarity);

	char n = 0;
	for(n=0;n<3;n++)
	{
		eeprom_write_word_inc(Pedals[(int)n].iMin);
		eeprom_write_word_inc(Pedals[(int)n].iMax);
		eeprom_write_word_inc(Pedals[(int)n].iFactor);
	}
	

	// finish eeprom update be clearing the busy flags:
	// initiate eeprom update by setting busy flags:
	eeprom_write_byte(EE_DUMMY, 0);
}


void LoadStandardConfig(void)
{
	char n = 0;
	for(n=0;n<3;n++)
	{
		Pedals[(int)n].iMin = 10;
		Pedals[(int)n].iMax = 1020;
		Pedals[(int)n].iFactor = 14;
	}	
}
